package com.flc.gateway.server;

import com.flc.gateway.Gateway;
import com.flc.gateway.dictionary.MessageType;
import com.flc.gateway.model.Command;
import com.flc.gateway.model.Message;
import com.flc.gateway.data.LoginData;
import com.flc.gateway.session.SessionManager;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.ReferenceCountUtil;

/**
 * @author haizi
 * @date 2017/12/31
 */
public class ServerHandler extends ChannelInboundHandlerAdapter {

    /**
     * 读数据
     * @param ctx ctx
     * @param msg 消息内容
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        try {
            //System.out.println("收到：" + ctx.channel().remoteAddress().toString());

            Message message = (Message) msg;

            if (message != null) {
                int messageType = message.getModule();
                switch (messageType) {
                    case MessageType.TRAJECTORY:
                        //ToDo  按照轨迹数据逻辑来处理
                        //1. 格式化为轨迹数据 - 放在消息队列之后处理
                        //2. 添加到轨迹数据消息队列
                        Gateway.trajectoryQueue.put(message.getData());
                        break;
                    case MessageType.REPORT:
                        //ToDo 按照报告数据来处理
                        //1. 格式化为报告数据 - 放在消息队列之后处理
                        //2. 添加到报告数据消息队列
                        Gateway.reportQueue.put(message.getData());
                        break;
                    case MessageType.DIAGNOSIS:
                        //ToDo 按照诊断数据来处理
                        //1. 格式化为诊断数据 - 放在消息队列之后处理
                        //2. 添加到诊断数据消息队列
                        Gateway.diagnosisQueue.put(message.getData());
                        break;
                    case MessageType.LOGIN:
                        //ToDo 按照设备登录逻辑来处理
                        // 1. 格式化登陆信息，创建session
                        // 2. 加入map<long deviceId, session>
                        LoginData loginData = new LoginData(message.getData());
                        SessionManager.registerSession(loginData.getDeviceId(), ctx.channel());
                        // 3. 添加至消息队列中一个新的设备上线的消息
                        Gateway.loginQueue.put(loginData);

                        break;
                    case MessageType.LOGOUT:
                        //ToDo 按照设备登出逻辑来处理 （理论上没有登出这个事件）
                        //1. 移除map中的session
                        //2. 添加至消息队列中一个设备离线的消息
                         break;
                    default:
                        //ToDo 错误数据，直接忽略
                        break;
                }
            }

        } finally {
            ReferenceCountUtil.release(msg);
        }
    }

    /**
     * 断开连接
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        super.channelInactive(ctx);
        System.out.println("断开：" + ctx.channel().remoteAddress());
        SessionManager.releaseSession(ctx.channel());
    }

    /**
     * 响应处理，心跳处理
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if(evt instanceof IdleStateEvent){
            IdleStateEvent event = (IdleStateEvent)evt;
            if (event.state() == IdleState.ALL_IDLE){
                Command cmd = new Command();
                cmd.setModule((short) 0x33);
                byte[] data = new byte[3];
                data[0] = 0x01;
                data[1] = 0x5f;
                data[2] = 0x73;
                cmd.setData(data);
                //清除超时会话
                ChannelFuture writeAndFlush = ctx.writeAndFlush(cmd);
                writeAndFlush.addListener((ChannelFutureListener) future -> ctx.channel().close());
            }
        }else{
            super.userEventTriggered(ctx, evt);
        }
    }


    /**
     * 异常处理
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
    }

    /**
     * Channel被注册到EventLoop上的时候并且能够处理IO的时候调用执行
     */
//    @Override
//    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
//        System.out.println(ctx.channel().remoteAddress().toString() + "===> channelRegistered");
//        //System.out.println(ctx.);
//        super.channelRegistered(ctx);
//    }

    /**
     * 当Channel从EventLoop中注销的时候且不能再处理I/O的时候调用执行
     */
    // @Override
//    public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
//        System.out.println(ctx.channel().remoteAddress().toString() + "===> channelUnregistered");
//        super.channelUnregistered(ctx);
//    }

    /**
     * 当Channel被激活时调用执行（已经准备好读写）
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("接入：" + ctx.channel().remoteAddress());
        super.channelActive(ctx);
    }

    /**
     * 读取完成后触发、断开连接前触发一次
     */
//    @Override
//    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
//        System.out.println(ctx.channel().remoteAddress().toString() + "===> channelReadComplete");
//        ctx.writeAndFlush(Unpooled.EMPTY_BUFFER);
//    }

//    @Override
//    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
//        System.out.println(ctx.channel().remoteAddress().toString() + "===> userEventTriggered");
//        super.userEventTriggered(ctx, evt);
//    }
//
//    @Override
//    public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception {
//        System.out.println(ctx.channel().remoteAddress().toString() + "===> channelWritabilityChanged");
//        super.channelWritabilityChanged(ctx);
//    }

}
